#include "EventLoop.h"
#include "Logger.h"
#include "Poller.h"
#include "Channel.h"

#include <sys/eventfd.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

// 防止一个线程创建多个EventLoop  thread_local
__thread EventLoop* t_loopInThisThread = nullptr;

// 定义默认的Poller IO复用的超时时间
const int kPollTimeMs = 1000;

// 创建wakeupfd，用来notify唤醒subReactor处理新来的channel
int createEventfd()
{
    int evtfd = ::eventfd(0,EFD_CLOEXEC | EFD_NONBLOCK);
    if(evtfd < 0)
    {
        LOG_FATAL("eventfd errot: %d\n",errno);
    }
}

EventLoop::EventLoop()
    :looping_(false)
    ,quit_(false)
    ,callingPendingFunctors_(false)
    ,threadId_(CurrentThread::tid())
    ,poller_(Poller::newDefaultPoller(this))
    ,wakeupFd_(createEventfd())
    ,wakeupChannel_(new Channel(this,wakeupFd_))
{
    LOG_DEBUG("EventLoop create %p in thread %d \n",this,threadId_);
    if(t_loopInThisThread)
    {
        LOG_FATAL("Another EventLoop %p exits in this thread %d \n",t_loopInThisThread,threadId_);
    }
    else
    {
        t_loopInThisThread = this;
    }

    // 设置wakeupfd的事件类型已经发生事件后的回调操作
    wakeupChannel_->setCloseCallback(std::bind(&EventLoop::handleRead,this));
    // 每一个eventloop都将监听wakeupchannel的POLLIN读事件了
    wakeupChannel_->enableReading();
}

EventLoop::~EventLoop()
{
    wakeupChannel_->disableAll();
    wakeupChannel_->remove();
    ::close(wakeupFd_);
    t_loopInThisThread = nullptr;
}

// 在当前loop中执行
void EventLoop::runInLoop(Functor cb)
{
    if(isInLoopThread()) // 在当前loop线程，中执行cb
    {
        cb();
    }
    else  // 在非当前loop线程，中执行cb，就需要唤醒loop所在线程，执行cb
    {
        queueInLoop(cb);
    }
}

// 把cd放入队列中，唤醒loop所在的线程，执行cb
void EventLoop::queueInLoop(Functor cb)
{
    {
        std::unique_lock<std::mutex> lock(mutex_);
        pendingFunctors_.emplace_back(cb);// push_back:拷贝构造 emplace_back:直接构造
    }

    // 唤醒响应的，需要执行上面回调操作的loop线程了
    // || callingPendingFunctors_的意思是：当前loop正在执行回调，但是loop又有了新的回调
    if(!isInLoopThread() || callingPendingFunctors_)
    {
        wakeup(); // 唤醒loop所在线程
    }
}

void EventLoop::handleRead() // 唤醒之后执行回调
{
    uint64_t one = 1;
    ssize_t n = read(wakeupFd_,&one,sizeof one);
    if(n != sizeof one)
    {
        LOG_ERROR("EventLoop::handleRead() read %d bytes instead of 8",n);
    }
}

// 开启事件循环
void EventLoop::loop()
{
    looping_ = true;
    quit_ = false;

    LOG_INFO("EventLoop %p start looping \n",this);

    while(!quit_)
    {
        activeChannels_.clear();
        // 监听两类fd  一种是client的fd，一种是wakeupfd
        pollReturnTime_ = poller_->poll(kPollTimeMs,&activeChannels_);
        for(Channel* channel : activeChannels_)
        {
            // Poller监听哪些channel发生事件了，然后上报给EventLoop 通知channel处理响应的事件
            channel->handleEvent(pollReturnTime_);
        }
        // 执行当前EventLoop事件循环需要处理的回调操作
        /*
        *    IO线程 mainLoop accept fd《= channel subloop
        *    mainLoop 事先注册一个回调cb(需要subloop来执行)  wakeip subloop后，执行下面的方法，执行之前mainloop注册的cb操作
        */
       doPendingFuncotrs();
    }

    LOG_INFO("EventLoop %p stop looping. \n",this);
    looping_ = false;
}
/*
*               mainLoop
*
*                                                      no========================生产者-消费者的线程安全的队列
*           通过自己的waupfd唤醒
*   subLoop1    subLoop2     subLoop3
*/
// 退出事件循环  1.loop在自己的线程中调用quit  2.在非loop的线程中，调用loop的quit
void EventLoop::quit()
{
    quit_ = true;

    // 如果实在其他线程中，调用quit   在一个subloop(worker)中，调用了mainLoop(IO)的quit
    if(!isInLoopThread())  
    {
        wakeup();// 所以要唤醒其他线程，其他线程才能退出
    }
}

 // 用来唤醒loop所在线程的   向wakefd_写一个数据,wakeupChannel就发生读事件，当前loop线程就会被唤醒
void EventLoop::wakeup()
{
    uint64_t one = 1;
    ssize_t n = write(wakeupFd_,&one,sizeof one);
    if(n != sizeof one)
    {
        LOG_ERROR("EventLoop::wakeup() write() %lu bytes instead of 8 \n",n);
    }
}

// EventLoop的方法 =》 Poller的方法
void EventLoop::updateChannel(Channel* channel)
{
    poller_->updateChannel(channel);    
}

void EventLoop::removeChannel(Channel* channel)
{
    poller_->removeChannel(channel);
}

bool EventLoop::hasChannel(Channel* channel)
{
    return poller_->hasChannele(channel);
}

void EventLoop::doPendingFuncotrs() // 执行回调
{
    // 定义个局部的vector，不要因为我在pendingFunctors_里面拿数据，因为锁而导致其他线程不能往里面放数据
    std::vector<Functor> functors;
    callingPendingFunctors_ = true;// 设置执行回调

    {
        std::unique_lock<std::mutex> lock(mutex_);
        functors.swap(pendingFunctors_);
    }

    for(const Functor& functor : functors)
    {
        functor(); // 执行当前loop需要执行的回调操作
    }

    callingPendingFunctors_ = false;
}